package ar.com.photo_admin.domain

import java.util.List

import org.springframework.dao.DataIntegrityViolationException
import grails.converters.*
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes

import ar.com.photo_admin.domain.sort.SortStrategy
import ar.com.photo_admin.service.UserService
import grails.plugins.springsecurity.Secured

@Secured(["isAuthenticated()"])
class EventController {
	
	final String IMAGES_PATH
	
	def springSecurityService
	
	def eventService
	
	def eventPhotoService
	
	def eventAlbumService
	
	def userService
	
	GrailsApplication grailsApplication
	
	static def MIN_FILE_SIZE = 1
	static def MAX_FILE_SIZE = 1000000 // 1MB
	static def THUMBNAIL_MODIFICATOR = ''
	static List ACCEPT_FILE_TYPES = [
		"image/jpeg",
		"image/png",
		"image/gif "
	]

    static allowedMethods = [save: "POST", update: "POST", delete: "POST", deleteAlbum: "POST"]

	def EventController(){
		IMAGES_PATH = grailsAttributes.getApplicationContext().getResource("images/upload").getFile().toString() + File.separatorChar
	}
	
    def index() {
        redirect(action: "list", params: params)		
    }

    def list() {
		User user = springSecurityService.currentUser
		
		params.max = 8
		params.sort = params.sort ? params.sort : SortStrategy.eventDate.name()
		params.order = params.order ? params.order : SortStrategy.eventDate.order
		
		def events = Event.allEvents(user, params.q).list(max: params.max, offset: params.offset, sort: params.sort, order: params.order)
		def eventSize = Event.allEvents(user, params.q).count()
		
        [events: events, eventSize: eventSize, sortStrategies: SortStrategy.values()]
    }
	
	@Secured(['ROLE_ADMIN'])
	def restore() {
		log.info "Restoring event: " + params.id
		
		def event = Event.get(params.id)
		
		if (!event) {
			flash.error = message(code: 'event.no.exist')
			redirect(action: "list")
			return
		}
		
		event.deleted = false
			
		if (event.save(flush:true)) {
			flash.message = message(code: 'event.restored')
		}
			
		redirect(action: "list")		
	}

	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
    def create() {
		log.info "Creating event"
		
		Event event = new Event(params)

		event.number =  eventService.getNextEventNumber()
		event.published = false
		 
		new File(IMAGES_PATH + event.number).mkdirs()
		new File(IMAGES_PATH + event.number + File.separator + grailsApplication.config.photos.path.notInHosting).mkdirs()
		new File(IMAGES_PATH + event.number + File.separator + grailsApplication.config.photos.path.inHosting).mkdirs()
		
        render(view: "uploadPhotos", model: [eventInstance: event, eventNumber : event.number, uploaded_files : [], coverPhotoId : 0, create: true])
    }

	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
	def save() {
		log.info "Saving event: " + params.id
		
		User user = springSecurityService.currentUser
		
		def eventId = params.id
		def coverPhotoId = params.coverId				
										
		def creating = (eventId == "")
		
		def eventInstance = null
		
		if (creating) {
			if (user.hasPhotographerRole() || user.hasAdminRole()) {
				eventInstance = new Event(params)
				eventInstance.number = (params.eventNumber).toInteger()
				eventInstance.photographer = user
			} else
				return
				
		} else {
			eventInstance = user.hasAdminRole() ? Event.allEvents(user).get(params.id) : Event.owned(user).get(params.id)
			eventInstance.properties = params
		}
		
		// Autocomplete of client name
		if (params.clientName != null && params.clientName.toString() != "") {
			def client = userService.loadUserFromAutocompleteText(params.clientName.toString())
			
			if(client == null)
				eventInstance.errors.rejectValue('client','client.doesnot.exist')
						
			eventInstance.client = client
		}
		else
			eventInstance.client = null
			
		if (eventInstance.hasErrors() || !eventInstance.save(flush: true)) {			
			// Validation failed. Get the photos that can be confirmed.			
			def existingPhotos = eventService.getEventConfirmedAndNotConfirmedPhotosAsJSON(eventInstance)
			render(view: "uploadPhotos", model: [eventInstance: eventInstance, 
												 eventNumber : eventInstance.number, 
												 coverPhotoId :coverPhotoId, 
												 uploaded_files : existingPhotos,
												 create: true,
												 clientName:params.clientName ])
			return
		}
		
		if (coverPhotoId != '0')
			eventInstance.coverPhoto = EventPhoto.get(coverPhotoId)
		
		// Client permissions are granted to the user.
		if (eventInstance.client != null)
			eventInstance.client.addClientRole()
	
		eventService.confirmChangesEvent(eventInstance)		
		flash.message = message(code: 'event.saved')
		
		// Check if album with all photos has to be created.
		if(creating && params.albumAllPhotosCreated)
			eventService.addAlbumWithAllPhotos(eventInstance)
			
		redirect(action: "show", id:eventInstance.id)
	}
	
    def show() {
		User user = springSecurityService.currentUser
		
        def event = Event.allEvents(user).get(params.id)
    
		if (!event) {
			flash.error = message(code: 'event.no.exist')
            redirect(action: "list")
			return
        }
		
		params.sort = params.sort ? params.sort : SortStrategy.dateCreated.name()
		params.order = params.order ? params.order : SortStrategy.dateCreated.order
		
		def albums = eventAlbumService.getAlbumsByEvent(event, [sort: params.sort, order: params.order])
				 
		[event: event, albums: albums, sortStrategies: [SortStrategy.dateCreated, SortStrategy.name]]
    }

	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
    def edit() {
		log.info "Editing event: " + params.eventId

		User user = springSecurityService.currentUser
		
		def event = user.hasAdminRole() ? Event.allEvents(user).get(params.eventId) : Event.owned(user).get(params.eventId)
		
		if (!event) {
			flash.error = message(code: 'event.no.exist')
			redirect(action: "list")
			return
		}
		
		// En caso de que no hubiera descartado los cambios correctamente, lo hace
		eventService.cancelChangesEvent(event)
		
		def clientName = event.client != null ? userService.autocompleteUserToString(event.client) : ""
		
		def coverId = (event.coverPhoto != null ? event.coverPhoto.id : 0 )
		
		def existingPhotosAsJSON = eventService.getEventPhotosAsJSON(event)
		
        render(view: "uploadPhotos", model: [eventInstance: event,
											 eventNumber : event.number,
											 coverPhotoId : coverId,
											 clientName: clientName,
											 uploaded_files : existingPhotosAsJSON, 
											 edit: true])		
    }
	
	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN', 'ROLE_CLIENT'])
	def deleteAlbum() {
		log.info "Deleting Album " + params.album_id + " from event " + params.event_id									
		
		User user = springSecurityService.getCurrentUser()
		
		EventAlbum album = EventAlbum.get(params.album_id)
		
		if (user.isAllowed(album)) {
			eventAlbumService.deleteAlbum(album)
			flash.message = message(code: 'eventAlbum.deleted')
		} else
			flash.message = message(code: 'eventAlbum.deleted.fail')
		
		redirect(action: "show", id: params.event_id)
	}

	/**
	 * Deletes an event. The event's photographer (or admin) is the only user that is allowed to do this operation. 
	 */
	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
	def delete() {
		log.info "Deleting event: " + params.id
		
		User user = springSecurityService.getCurrentUser()
		
		def event = user.hasAdminRole() ? Event.allEvents(user).get(params.id) : Event.ownedAsPhotographer(user).get(params.id)
		
		if (!event) {
			flash.error = message(code: 'event.no.exist')
			redirect(action: "list")
			return
		}

		event.deleted = true
			
		if (event.save(flush:true)) {
			flash.message = message(code: 'event.deleted')
		}
					
		redirect(action: "list")
	}
	
	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
	def cancel() {
		log.info "Canceling event: " + params.eventId
		
		if (params.eventId) {
			User user = springSecurityService.getCurrentUser()
			
			def event = user.hasAdminRole() ? Event.allEvents(user).get(params.eventId) : Event.owned(user).get(params.eventId)
			
			if (!event) {
				response.sendError 500, 'Event doesnt exist'
				return
			}
			
			eventService.cancelChangesEvent(event)
		}
		else {
			eventService.cancelNewEvent(params.eventNumber)
		}
		
		flash.message = message(code: 'event.photoUpload.canceled', default: "Los cambios fueron descartados")
		
		render(success: true)
	}
	
	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
	def deleteSelectedPhotosTemporally() {
		log.info "Deleting selected photos: " + params.ids
		
		def idsToBeDeleted = (params.ids).split(",")
		
		idsToBeDeleted.each {
			eventService.deletePhotoTemporally(it)
		}
		
		render(success: true)
	}

	@Secured(['ROLE_PHOTOGRAPHER', 'ROLE_ADMIN'])
	def uploadAction() {
		// Uploaded images collection.
		def results = []

		// Uploaded images properties.
		def result = [:]

		// Sometimes content type is null.
		if (request.getContentType() != null) {
			log.info "Uploading image in event: " + params.eventNumber
				
			User user = springSecurityService.getCurrentUser()
			
			def eventNumber = params.eventNumber
			Event event = Event.findByNumber(eventNumber)
			
			if (event != null && !user.isOwner(event))
				return

			DefaultMultipartHttpServletRequest filesRequest = (DefaultMultipartHttpServletRequest) request

			Iterator itr = filesRequest.getFileNames()

			def photoDir

			while(itr.hasNext()) {
					
				def file = filesRequest.getFile(itr.next())

				def fileName = file.getOriginalFilename()
				result['name'] = fileName
				result['size'] = file.getSize()
				result['type'] = file.getContentType()

				def validationResult = validateFile(result)

				if (validationResult) {
															
					EventPhoto photo = eventPhotoService.createPhotoTemporally(eventNumber, file.getBytes(), file.getOriginalFilename())
					
					result['photoId'] = photo.id
					result['url'] = photo.url
					result['thumbnailUrl'] = photo.thumbnailUrl
				}
				else{
					result['delete_type'] = 'DELETE'
				}

				results << result
			}
		}
		
		render results as JSON
	}

	def validateFile(result) {
		if (result['size'] < MIN_FILE_SIZE){
			result['error'] = 'minFileSize'
			return false
		}
			
		else if (result['size'] > MAX_FILE_SIZE){
			result['error'] = 'maxFileSize'
			return false
		}
		else if (! ACCEPT_FILE_TYPES.contains(result['type'])){
			result['error'] = 'acceptFileTypes'
			return false
		}
		else
			return true
	}
}